package cn.thoughtworks.school.controllers;

import cn.thoughtworks.school.annotations.Auth;
import cn.thoughtworks.school.entities.SimpleCodingQuiz;
import cn.thoughtworks.school.entities.SimpleCodingSubmission;
import cn.thoughtworks.school.entities.User;
import cn.thoughtworks.school.handlers.BusinessException;
import cn.thoughtworks.school.repositories.SimpleCodingQuizRepository;
import cn.thoughtworks.school.repositories.SimpleCodingQuizSubmissionRepository;
import cn.thoughtworks.school.requestParams.CreateSimpleCodingParam;
import cn.thoughtworks.school.services.AmazonClientService;
import cn.thoughtworks.school.services.SimpleCodingQuizService;
import cn.thoughtworks.school.services.UserCenterService;
import cn.thoughtworks.school.services.Utils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.web.PageableDefault;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static cn.thoughtworks.school.services.Utils.readFileToString;

@RestController
@RequestMapping(value = "/api/simpleCodingQuizzes")
@Slf4j
public class SimpleCodingQuizController {

  @Autowired
  private AmazonClientService amazonClientService;
  @Autowired
  private SimpleCodingQuizService simpleCodingQuizService;
  @Autowired
  private SimpleCodingQuizRepository simpleCodingQuizRepository;
  @Autowired
  private SimpleCodingQuizSubmissionRepository simpleCodingQuizSubmissionRepository;
  @Autowired
  private Utils utils;

  @GetMapping(value = "pageable")
  public ResponseEntity getSimpleCodingQuizzesPageable(@PageableDefault(sort = {"id"}, direction = Sort.Direction.DESC) Pageable pageable,
                                                   @RequestParam(required = false) Long quizId,
                                                   @RequestParam(required = false) Long userId,
                                                   @RequestParam(required = false) String description,
                                                   @RequestParam(required = false) List<String> tags,
                                                   @Auth User user) {
    Page simpleCodingQuizzesPage = simpleCodingQuizService.getSimpleCodingQuizzesPageable(pageable,quizId,userId,description,tags,user);
    return new ResponseEntity<>(simpleCodingQuizzesPage, HttpStatus.OK);
  }
  @PostMapping("")
  @Transactional
  public ResponseEntity addSimpleCoding(@RequestBody CreateSimpleCodingParam params, @Auth User user) {
    SimpleCodingQuiz simpleCodingQuiz = simpleCodingQuizService.addSimpleCodingQuiz(params, user);
    return new ResponseEntity(simpleCodingQuiz, HttpStatus.CREATED);
  }

  @PutMapping("")
  @Transactional
  public ResponseEntity editSimpleCoding(@RequestBody CreateSimpleCodingParam params, @Auth User user) throws BusinessException {
    simpleCodingQuizService.editSimpleCodingQuiz(params, user);
    return new ResponseEntity(HttpStatus.NO_CONTENT);
  }

  @GetMapping("{id}")
  public ResponseEntity getSimpleCodingById(@PathVariable Long id) throws BusinessException {
    SimpleCodingQuiz homeworkQuiz = simpleCodingQuizRepository.findById(id)
      .orElseThrow(() -> new BusinessException("编程题不存在"));
    return new ResponseEntity(homeworkQuiz, HttpStatus.OK);
  }

  @PutMapping("{id}/status")
  public ResponseEntity updateStatus(@PathVariable Long id,
                                     @RequestParam(value = "message", required = false) MultipartFile message) throws BusinessException {
    SimpleCodingQuiz homeworkQuiz = simpleCodingQuizRepository.findById(id).orElseThrow(() ->
      new BusinessException("编程题不存在"));
    String description = readFileToString(message);
    homeworkQuiz.setJobMessage(description);
    simpleCodingQuizRepository.save(homeworkQuiz);
    return new ResponseEntity(HttpStatus.NO_CONTENT);
  }

  @PutMapping("{id}/answerFile")
  public ResponseEntity updateAnswerFile(@PathVariable Long id,
                                         @RequestParam(value = "answer", required = false) MultipartFile answer,
                                         @RequestParam(value = "buildNumber", required = false) Long buildNumber) throws IOException, BusinessException {
    SimpleCodingQuiz homeworkQuiz = simpleCodingQuizRepository
      .findById(id)
      .orElseThrow(() -> new BusinessException(
        String.format("Unknown homeworkQuiz with id: %s", id)
      ));

    String answerPath = saveFile(answer, "homework-answer");
    homeworkQuiz.setAnswerPath(answerPath);
    homeworkQuiz.setBuildNumber(buildNumber);
    simpleCodingQuizRepository.save(homeworkQuiz);
    return new ResponseEntity<>(HttpStatus.NO_CONTENT);
  }

  @GetMapping("{quizId}/answerFile")
  public void getHomeworkQuizzes(@PathVariable Long quizId,
                                 HttpServletResponse response) throws IOException, BusinessException {
    SimpleCodingQuiz simpleCodingQuiz = simpleCodingQuizRepository
      .findById(quizId)
      .orElseThrow(() -> new BusinessException(
        String.format("Unknown homeworkQuiz with id: %s", quizId)
      ));
    InputStream inputStream = amazonClientService.getInputStream(simpleCodingQuiz.getAnswerPath(), "homework-answer");
    IOUtils.copy(inputStream, response.getOutputStream());
    response.flushBuffer();
  }

  @PutMapping("{id}/scriptFile")
  public ResponseEntity updateScriptFile(@PathVariable Long id,
                                         @RequestParam(value = "script", required = false) MultipartFile script) throws BusinessException {
    SimpleCodingQuiz homeworkQuiz = simpleCodingQuizRepository
      .findById(id)
      .orElseThrow(() -> new BusinessException(
        String.format("Unknown homeworkQuiz with id: %s", id)
      ));

    String evaluateScript = saveFile(script, "homework-script");
    homeworkQuiz.setEvaluateScript(evaluateScript);
    simpleCodingQuizRepository.save(homeworkQuiz);
    return new ResponseEntity<>(HttpStatus.NO_CONTENT);
  }

  @PutMapping("{id}/templateRepository")
  public ResponseEntity updateTemplateRepository(@PathVariable Long id,
                                                 @RequestParam(value = "templateRepository", required = false) String templateRepository) throws BusinessException {

    SimpleCodingQuiz homeworkQuiz = simpleCodingQuizRepository
      .findById(id)
      .orElseThrow(() -> new BusinessException(
        String.format("Unknown homeworkQuiz with id: %s", id)
      ));

    homeworkQuiz.setTemplateRepository(templateRepository);
    simpleCodingQuizRepository.save(homeworkQuiz);
    return new ResponseEntity<>(HttpStatus.NO_CONTENT);
  }

  @PutMapping("{id}/result/{status}")
  public ResponseEntity updateResult(@PathVariable Long id,
                                     @PathVariable Integer status,
                                     @RequestParam(value = "message") MultipartFile message) throws BusinessException {
    SimpleCodingQuiz homeworkQuiz = simpleCodingQuizRepository
      .findById(id)
      .orElseThrow(() -> new BusinessException(
        String.format("Unknown homeworkQuiz with id: %s", id)
      ));

    String jobMessage = readFileToString(message);
    homeworkQuiz.setJobMessage(jobMessage);
    homeworkQuiz.setStatus(status);
    simpleCodingQuizRepository.save(homeworkQuiz);
    return new ResponseEntity<>(HttpStatus.NO_CONTENT);
  }


  private String saveFile(MultipartFile file, String directory) {

    return amazonClientService.uploadFile(file, directory);
  }


  @GetMapping("/{id}/status")
  public ResponseEntity getAddHomeworkLog(@PathVariable Long id) throws BusinessException {
    SimpleCodingQuiz homeworkQuiz = simpleCodingQuizRepository
      .findById(id)
      .orElseThrow(() -> new BusinessException(
        String.format("Unknown homeworkQuiz with id: %s", id)
      ));

    return new ResponseEntity<>(homeworkQuiz, HttpStatus.OK);
  }

  @DeleteMapping("/{id}")
  @Transactional
  public ResponseEntity deleteById(@PathVariable Long id) throws BusinessException {
    simpleCodingQuizService.deleteById(id);
    return new ResponseEntity<>(HttpStatus.NO_CONTENT);
  }

  @RequestMapping(value = "/students/{studentId}/assignments/{assignmentId}/quizzes/{ids}", method = RequestMethod.GET)
  public ResponseEntity getSimpleCodingQuizzesWithUserAnswer(@PathVariable Long studentId, @PathVariable Long assignmentId, @PathVariable String ids) {
    List<Long> idList = Arrays.stream(ids.split(","))
      .map(Long::parseLong)
      .collect(Collectors.toList());
    List<SimpleCodingQuiz> quizzes = simpleCodingQuizRepository.findByIdInAndIsAvailableIsTrue(idList);
    List<SimpleCodingSubmission> quizSubmissions = simpleCodingQuizSubmissionRepository.findByQuizIdInAndAssignmentIdAndUserIdOrderByIdDesc(idList, assignmentId, studentId);

    List<Map> results = quizzes.stream()
      .map(quiz -> utils.addUserAnswer(quiz, quizSubmissions))
      .collect(Collectors.toList());

    return new ResponseEntity<>(results, HttpStatus.OK);
  }
}
